#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h> 
#include <cstdlib>
#include <sys/socket.h>
 #include <arpa/inet.h>
       #include <netinet/in.h>
#include<cstring>
#include"Log.hpp"
#include<functional>
#include<unordered_map>
uint16_t defaultport = 8080;
const int size = 1024;

typedef  std::function<std::string (const std::string &, const std::string &  ,uint16_t     )> func_t ; 


std::string defaultip = "0.0.0.0";
enum 
{
  SOCKET_ERR=1,
    BIND_ERR
};
Log lg;
class UdpServer
{
public:
    UdpServer(const   uint16_t &port = defaultport,const std::string &ip = defaultip)
        : sockfd_(0), ip_(ip), port_(port), isrunning_(false)
    {
    }

    void Init()
    {
        // 1. 创建udp socket
      sockfd_=  socket(AF_INET,SOCK_DGRAM,0) ;//网路通信IPv4
        
        if(sockfd_<0 )
        {
            lg(SOCKET_ERR,  "socket create error, sockfd: %d", sockfd_);
             exit(SOCKET_ERR);
        }
            lg(Info, "socket create success, sockfd: %d", sockfd_);
             // 2. bind socket
         struct sockaddr_in local;
        bzero(&local, sizeof(local));  //将local的内存清零
        local.sin_family =AF_INET;//网路通信IPv4
        local.sin_port= htons(port_); //保证端口号是网络字节序列，因为该端口号是要给对方发送的
         //string 变为 uint32_t  ,uint32_t必须是网络序列

        local.sin_addr.s_addr =  inet_addr(ip_.c_str());
         //local.sin_addr.s_addr = htonl(INADDR_ANY);  //INADDR_ANY就是0 
       //绑定
       if(bind(sockfd_ ,(const struct sockaddr *)&local  ,sizeof(local) ) < 0   )
       {
           lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
             exit(BIND_ERR);
       }
        lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));  

    }


void CheckUser( const struct sockaddr_in & client, const uint16_t  clientport, const std::string   clientip)
{
  

     //没有找到client的ip 
    if(online_user_.find(clientip)  ==online_user_.end())
    {
        online_user_.insert({clientip,client});
        std::cout<<"["<<clientip << ":" <<clientport<<"] add to online user . " <<std::endl;
    }
    //找到了client的ip什么也不做


}

void Broadcast(std::string & info,  const std::string   clientip ,const uint16_t  clientport)
{

        //将消息发送给用户列表的所有人
    for(const auto & user : online_user_)
    {
        std::string  message = "[";
        message+= clientip ;
        message+=":" ;
        message += std::to_string(clientport);
        message+="]#" ;
        message+=info ;
        socklen_t len  = sizeof(user.second);
        sendto(sockfd_,message.c_str(),message.size() ,0, (struct  sockaddr *) &(user.second) , len);
    }


}
    //void Run(func_t func)
        void Run()
    {
  
       char inbuffer[size] ;
        isrunning_  =true ;
        while(isrunning_)
        {
            
                 //收数据
                 struct sockaddr_in  client ;
            socklen_t  len  = sizeof(client) ;
            ssize_t n =recvfrom(sockfd_,inbuffer,sizeof(inbuffer) - 1 , 0 ,(struct sockaddr  *)&client, &len );
   
                  if(n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }

            
  uint16_t clientport = ntohs(client.sin_port);
     std::string clientip =  inet_ntoa(client.sin_addr) ;
                CheckUser(client,clientport,clientip) ;


                  //数据处理
                inbuffer[n] = 0; //把inbuffer当字符串处理 
                std::string info  = inbuffer;
                std::string echo_string = info ;

            Broadcast(info ,clientip,clientport);//将消息发送给所有人

            //发数据
                std::cout<<echo_string<<std::endl;
                sendto( sockfd_ ,echo_string.c_str() ,echo_string.size(),0,(struct sockaddr  *)&client ,len) ;
               

        }

           


    }

    ~UdpServer()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }

private:
    int sockfd_;     // 网路文件描述符
    std::string ip_; // 任意地址bind 0
    uint16_t port_;  // 表明服务器进程的端口号
    bool isrunning_; //服务是否在运行
    std::unordered_map<std::string ,  struct sockaddr_in >   online_user_;  //ip ,套接字 ,实现一个用户列表
};